﻿//----------------------------------------------------------------
// Desc: 区域
// Edit: ShowLong, http://blog.csdn.net/showlong
//
// Date Created: 2010-06-30
//
// Update Date : 
//
// Copyright (c) Fuel4D (http://www.fuel4d.com), All rights reserved.
//
//----------------------------------------------------------------
#pragma once


#pragma pack(push, 1)


struct FRect
{
    FDECLARE_STRUCT(FRect)

    FINLINE FRect()
        :X(0)
        ,Y(0)
        ,W(0)
        ,H(0)
    {}
    FRect(float x, float y, float w, float h)
        :X(x)
        ,Y(y)
        ,W(w)
        ,H(h)
    {}
    FINLINE FRect(const FRect& rc)
        :X(rc.X)
        ,Y(rc.Y)
        ,W(rc.W)
        ,H(rc.H)
    {}
    FINLINE FRect(FVECTOR2& pos, FVECTOR2& size)
        :X(pos.x)
        ,Y(pos.y)
        ,W(size.x)
        ,H(size.y)
    {}
    FINLINE bool equals(FRect& rt)
    {
        return operator==(rt);
    }
    FINLINE void clear()
    {
        X = Y = W = H = 0;
    }
    FINLINE void get_position(float& dx, float& dy)
    {
        dx = X, dy = Y;
    }
    FINLINE void get_position(FVECTOR2& pos)
    {
        pos.x = X, pos.y = Y;
    }
    FINLINE void get_size(float& dw, float& dh)
    {
        dw = W, dh = H;
    }
    FINLINE void get_size(FVECTOR2& size)
    {
        size.x = W, size.y = H;
    }
    // 测试坐标是否在自己内部
    FINLINE bool inside(float x, float y)
    {
        return (x >= X && x < (X + W) && y >= Y && y < (Y + H));
    }
    FINLINE bool inside(FVECTOR2& pos)
    {
        return inside(pos.x, pos.y);
    }
    // 测试区域是否在自己内部
    FINLINE bool inside(const FRect& rc)
    {
        return (X <= rc.X) && (rc.X+rc.W <= X+W) &&
               (Y <= rc.Y) && (rc.Y+rc.H <= Y+H);
    }
    FINLINE void set(float x, float y, float w, float h)
    {
        X = x, Y = y, W = w, H = h;
    }
    FINLINE void get(float& x, float& y, float& w, float& h)
    {
        x = X, y = Y, w = W, h = H;
    }
    // 扩张或者收缩
    FINLINE void inflate(float v)
    {
        inflate(v, v);
    }
    FINLINE void inflate(FVECTOR2& i)
    {
        inflate(i.x, i.y);
    }
    FINLINE void inflate(float x, float y)
    {
        X -= x, Y -=y, W += x*2.0f, H += y*2.0f;
    }
    // 坐标偏移
    FINLINE void offset(float x, float y)
    {
        X += x, Y += y;
    }
    FINLINE void offset(FVECTOR2& o)
    {
        offset(o.x, o.y);
    }
    // 移动到目标位置
    FINLINE void move_to(float x, float y)
    {
        X = x, Y = y;
    }
    FINLINE void move_to(FVECTOR2& o)
    {
        move_to(o.x, o.y);
    }
    // 设置坐标
    FINLINE void set_pos(float x, float y)
    {
        X = x, Y = y;
    }
    FINLINE void set_pos(FVECTOR2& n)
    {
        set_size(n.x, n.y);
    }
    // 设置尺寸
    FINLINE void set_size(float w, float h)
    {
        W = w, H = h;
    }
    FINLINE void set_size(FVECTOR2& n)
    {
        set_size(n.x, n.y);
    }
    // 交集
    FINLINE bool intersect(FRect& rc)
    {
        float rt = FMin(right(), rc.right());
        float bt = FMin(bottom(), rc.bottom());
        float lt = FMax(left(), rc.left());
        float tp = FMax(top(), rc.top());
        X = lt, Y = tp, W = rt - lt, H = bt - tp;
        bool ret = (W > 0 && H > 0);
        if (!ret)
            clear();
        return ret;
    }
    // 测试交叉
    FINLINE bool test_intersect(FRect& rc)
    {
        float rt = FMin(right(), rc.right());
        float bt = FMin(bottom(), rc.bottom());
        float lt = FMax(left(), rc.left());
        float tp = FMax(top(), rc.top());
        float w = rt - lt, h = bt - tp;
        return (w > 0 && h > 0);
    }
    // 合并
    FINLINE bool union_rect(FRect& rc)
    {
        float rt = FMax(right(), rc.right());
        float bt = FMax(bottom(), rc.bottom());
        float lt = FMin(left(), rc.left());
        float tp = FMin(top(), rc.top());
        X = lt, Y = tp, W = rt - lt, H = bt - tp;
        bool ret = (W > 0 && H > 0);
        if (!ret)
            clear();
        return ret;
    }
    FINLINE float left()
    {
        return X;
    }
    FINLINE float top()
    {
        return Y;
    }
    FINLINE float right()
    {
        return X + W;
    }
    FINLINE float bottom()
    {
        return Y + H;
    }
    FINLINE bool is_empty() const
    {
        return (W <= 0 && H <= 0);
    }
    FINLINE operator float* ()
    {
        return (float *) &X;
    }
    FINLINE operator const float* () const
    {
        return (const float *) &X;
    }
    FINLINE FRect& operator += ( const FRect& v )
    {
        X += v.X;
        Y += v.Y;
        W += v.W;
        H += v.H;
        return *this;
    }
    FINLINE FRect& operator -= ( const FRect& v )
    {
        X -= v.X;
        Y -= v.Y;
        W -= v.W;
        H -= v.H;
        return *this;
    }
    FINLINE FRect& operator *= ( float f )
    {
        X *= f;
        Y *= f;
        W *= f;
        H *= f;
        return *this;
    }
    FINLINE FRect& operator /= ( float f )
    {
        float fInv = 1.0f / f;
        X *= fInv;
        Y *= fInv;
        W *= fInv;
        H *= fInv;
        return *this;
    }
    FINLINE FRect operator + () const
    {
        return *this;
    }
    FINLINE FRect operator - () const
    {
        return FRect(-X, -Y, -W, -H);
    }
    FINLINE FRect operator + ( const FRect& v ) const
    {
        return FRect(X + v.X, Y + v.Y, W + v.W, H + v.H);
    }
    FINLINE FRect operator - ( const FRect& v ) const
    {
        return FRect(X - v.X, Y - v.Y, W - v.W, H - v.H);
    }
    FINLINE FRect operator * ( float f ) const
    {
        return FRect(X * f, Y * f, W * f, H * f);
    }
    FINLINE FRect operator / ( float f ) const
    {
        float fInv = 1.0f / f;
        return FRect(X * fInv, Y * fInv, W * fInv, H * fInv);
    }
    FINLINE bool operator == ( const FRect& v ) const
    {
        return X == v.X && Y == v.Y && W == v.W && H == v.H;
    }
    FINLINE bool operator != ( const FRect& v ) const
    {
        return X != v.X || Y != v.Y || W != v.W || H != v.H;
    }

    float X, Y, W, H;

    // 生成九宫目标(nineRect[9])
    FINLINE void make_dst_ninepal(FRect* dstRect, FRect* srcRect, FRect* center, FRect* nineRect);
    // 生成九宫图片源区域(nineRect[9])
    FINLINE void make_src_ninepal(FRect* srcRect, FRect* center, FRect* nineRect);
    // 生成目标三宫(threeRect[3])
    FINLINE void make_dst_threepal(FRect* dstRect, FRect* srcRect, FRect* center, FRect* threeRect, bool horizontal);
    // 生成源三宫(threeRect[3])
    FINLINE void make_src_threepal(FRect* srcRect, FRect* center, FRect* threeRect, bool horizontal);

protected:
    FINLINE void fill_ninepal(FRect* nineRect, float& w1, float& w2, float& w3, float& h1, float& h2, float& h3, float dstx, float dsty);
};


#pragma pack(pop)


typedef FVector< FRect >            FV_FRECT;
typedef FVector< FRect* >           FV_PFRECT;


FINLINE void FRect::make_dst_ninepal(FRect* dstRect, FRect* srcRect, FRect* center, FRect* nineRect)
{
    FASSERT(!center->is_empty(), _FT("数据异常"));
    FASSERT(center->X + center->W < srcRect->W, _FT("数据异常"));
    FASSERT(center->Y + center->H < srcRect->H, _FT("数据异常"));

    //RECT rCenter;
    //center->get_gdiplus(&rCenter);

    float w1 = center->X;
    float w3 = srcRect->W - (center->X + center->W) - 1;
    float w2 = dstRect->W - w1 - w3;
    float h1 = center->Y;
    float h3 = srcRect->H - (center->Y + center->H) - 1;
    float h2 = dstRect->H - h1 - h3;

    fill_ninepal(nineRect, w1, w2, w3, h1, h2, h3, dstRect->X, dstRect->Y);
}
FINLINE void FRect::make_src_ninepal(FRect* srcRect, FRect* center, FRect* nineRect)
{
    FASSERT(!center->is_empty(), _FT("数据异常"));
    FASSERT(center->X + center->W < srcRect->W, _FT("数据异常"));
    FASSERT(center->Y + center->H < srcRect->H, _FT("数据异常"));

    //RECT rCenter;
    //center->get_gdiplus(&rCenter);

    float w1 = center->X;
    float w3 = srcRect->W - (center->X + center->W) - 1;
    float w2 = srcRect->W - w1 - w3;
    float h1 = center->Y;
    float h3 = srcRect->H - (center->Y + center->H) - 1;
    float h2 = srcRect->H - h1 - h3;

    fill_ninepal(nineRect, w1, w2, w3, h1, h2, h3, srcRect->X, srcRect->Y);
}
FINLINE void FRect::make_dst_threepal(FRect* dstRect, FRect* srcRect, FRect* center, FRect* threeRect, bool horizontal)
{
    FASSERT(!center->is_empty(), _FT("数据异常"));

    //RECT rCenter;
    //center->get_gdiplus(&rCenter);

    if (horizontal)
    {
        float w1 = center->X;
        float w3 = srcRect->W - (center->X + center->W) - 1;
        float w2 = dstRect->W - w1 - w3;
        float h  = dstRect->H;

        if (w2 < 0)
        {
            w2 = 0;
            if (dstRect->W > w3)
                w1 = dstRect->W - w3;
            else if (dstRect->W < w3)
                w1 = 0, w3 = dstRect->W;
            else
                w1 = 0;
        }

        threeRect[0].set(0, 0, w1, h);
        threeRect[1].set(w1, 0, w2, h);
        threeRect[2].set(w1 + w2, 0, w3, h);
    }
    else
    {
        float h1 = center->Y;
        float h3 = srcRect->H - (center->Y + center->H) - 1;
        float h2 = dstRect->H - h1 - h3;
        float w  = dstRect->W;

        if (h2 < 0)
        {
            h2 = 0;
            if (dstRect->H > h3)
                h1 = dstRect->H - h3;
            else if (dstRect->H < h3)
                h1 = 0, h3 = dstRect->H;
            else
                h1 = 0;
        }

        threeRect[0].set(0, 0, w, h1);
        threeRect[1].set(0, h1, w, h2);
        threeRect[2].set(0, h1 + h2, w, h3);
    }

    threeRect[0].offset(dstRect->X, dstRect->Y);
    threeRect[1].offset(dstRect->X, dstRect->Y);
    threeRect[2].offset(dstRect->X, dstRect->Y);
}
FINLINE void FRect::make_src_threepal(FRect* srcRect, FRect* center, FRect* threeRect, bool horizontal)
{
    FASSERT(!center->is_empty(), _FT("数据异常"));

    //RECT rCenter;
    //center->get_gdiplus(&rCenter);

    if (horizontal)
    {
        float w1 = center->X;
        float w3 = srcRect->W - (center->X + center->W) - 1;
        float w2 = srcRect->W - w1 - w3;
        float h  = srcRect->H;

        threeRect[0].set(0, 0, w1, h);
        threeRect[1].set(w1, 0, w2, h);
        threeRect[2].set(w1 + w2, 0, w3, h);
    }
    else
    {
        float h1 = center->Y;
        float h3 = srcRect->H - (center->Y + center->H) - 1;
        float h2 = srcRect->H - h1 - h3;
        float w  = srcRect->W;

        threeRect[0].set(0, 0, w, h1);
        threeRect[1].set(0, h1, w, h2);
        threeRect[2].set(0, h1 + h2, w, h3);
    }

    threeRect[0].offset(srcRect->X, srcRect->Y);
    threeRect[1].offset(srcRect->X, srcRect->Y);
    threeRect[2].offset(srcRect->X, srcRect->Y);
}

FINLINE void FRect::fill_ninepal(FRect* nineRect, float& w1, float& w2, float& w3, float& h1, float& h2, float& h3, float dstx, float dsty)
{
    nineRect[0].set(0, 0, w1, h1);
    nineRect[1].set(w1, 0, w2, h1);
    nineRect[2].set(w1 + w2, 0, w3, h1);

    nineRect[3].set(0, h1, w1, h2);
    nineRect[4].set(w1, h1, w2, h2);
    nineRect[5].set(w1 + w2, h1, w3, h2);

    nineRect[6].set(0, h1 + h2, w1, h3);
    nineRect[7].set(w1, h1 + h2, w2, h3);
    nineRect[8].set(w1 + w2, h1 + h2, w3, h3);

    nineRect[0].offset(dstx, dsty);
    nineRect[1].offset(dstx, dsty);
    nineRect[2].offset(dstx, dsty);
    nineRect[3].offset(dstx, dsty);
    nineRect[4].offset(dstx, dsty);
    nineRect[5].offset(dstx, dsty);
    nineRect[6].offset(dstx, dsty);
    nineRect[7].offset(dstx, dsty);
    nineRect[8].offset(dstx, dsty);
}